﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Input.Touch;
using Microsoft.Xna.Framework.Audio;

namespace LaserShow
{
    /// <summary>
    /// Keep track of spawning and killing dots
    /// </summary>
    static class DotManager
    {
        /// <summary>
        /// List of lasers currently on the screen
        /// </summary>
        private static List<Laser> lasers;

        /// <summary>
        /// A spritefont
        /// </summary>
        public static SpriteFont ui;

        public static SpriteFont subui;

        private static SoundEffect laser;

        public static float[] pitches;


        static DotManager()
        {
            lasers = new List<Laser>();

            float halfstep = 1 / 12f;

            pitches = new float[5];
            pitches[0] = halfstep * 0;
            pitches[1] = halfstep * 2;
            pitches[2] = halfstep * 4;
            pitches[3] = halfstep * 7;
            pitches[4] = halfstep * 9;
        }


        /// <summary>
        /// Load all dot graphics
        /// </summary>
        /// <param name="content"></param>
        public static void LoadContent(ContentManager content)
        {
            ui = content.Load<SpriteFont>("ui");
            subui = content.Load<SpriteFont>("subui");

            laser = content.Load<SoundEffect>("lasersnd");

            Laser.LoadContent(content);
        }

        /// <summary>
        /// Reset all dots and patterns
        /// </summary>
        public static void Reset()
        {
            lasers.Clear();
        }

        /// <summary>
        /// Take input to kill dots
        /// </summary>
        public static void TakeInput(TouchCollection input)
        {
            foreach (TouchLocation t in input)
            {
                if (t.State == TouchLocationState.Pressed)
                {
                    lasers.Add(new Laser(t.Position));
                    PlaySound(laser);
                }
            }
        }

        private static List<SoundEffectInstance> soundInstances = new List<SoundEffectInstance>();

        /// <summary>
        /// Play the specified sound
        /// </summary>
        /// <param name="sound"></param>
        public static void PlaySound(SoundEffect sound)
        {
            SoundEffectInstance inst = sound.CreateInstance();
            inst.Pitch = pitches[Global.rand.Next(pitches.Length)];
            inst.Play();
            soundInstances.Add(inst);
        }

        /// <summary>
        /// Update spawning of dots
        /// </summary>
        /// <param name="gameTime"></param>
        public static void Update(GameTimerEventArgs gameTime)
        {
            //Calculate points for each kill
            for (int c = lasers.Count - 1; c >= 0; c--)
            {
                lasers[c].Update(gameTime);

                //Remove laser
                if (lasers[c].Dead)
                {
                    lasers.RemoveAt(c);
                }
            }
        }

        /// <summary>
        /// Draw all dots
        /// </summary>
        /// <param name="spriteBatch"></param>
        public static void Draw(SpriteBatch spriteBatch)
        {
            foreach (Laser l in lasers)
                l.Draw(spriteBatch);
        }


        /// <summary>
        /// Represents a laser hit on the screen
        /// </summary>
        private class Laser
        {
            /// <summary>
            /// The screen position of the center of the laser
            /// </summary>
            public Vector2 position { get; private set; }

            /// <summary>
            /// The time this laser has left to live
            /// </summary>
            private TimeSpan lifeTime;

            /// <summary>
            /// Laser overall lifetime
            /// </summary>
            private static TimeSpan totalLifeTime = new TimeSpan(0, 0, 0, 0, 300);

            /// <summary>
            /// The width of the actual laser.
            /// </summary>
            private static int laserSize = 5;

            /// <summary>
            /// The laser graphic
            /// </summary>
            private static Texture2D graphic;

            /// <summary>
            /// Is this laser expired?
            /// </summary>
            public bool Dead { get { return lifeTime <= TimeSpan.Zero; } }

            private Color color;


            /// <summary>
            /// Make a new laser object
            /// </summary>
            /// <param name="position"></param>
            public Laser(Vector2 position)
            {
                this.position = position;
                this.lifeTime = totalLifeTime;

                color = new Color(
                    Global.rand.Next(255),
                    Global.rand.Next(255),
                    Global.rand.Next(255));
            }

            /// <summary>
            /// Load the laser graphic
            /// </summary>
            /// <param name="content"></param>
            public static void LoadContent(ContentManager content)
            {
                graphic = content.Load<Texture2D>("laser");
            }

            /// <summary>
            /// Update the laser
            /// </summary>
            /// <param name="e"></param>
            public void Update(GameTimerEventArgs e)
            {
                lifeTime -= e.ElapsedTime;
            }

            /// <summary>
            /// Draw the laser
            /// </summary>
            /// <param name="batch"></param>
            public void Draw(SpriteBatch batch)
            {
                Color color = new Color(this.color.R, this.color.G, this.color.B, 255
                    (byte)(255 * (float)(lifeTime.TotalMilliseconds / totalLifeTime.TotalMilliseconds))
                    );
                batch.Draw(
                    graphic,
                    position,
                    null,
                    color,
                    0.0f,
                    new Vector2(0, graphic.Height),
                    1.0f,
                    SpriteEffects.None,
                    1.0f);
                batch.Draw(
                    graphic,
                    position,
                    null,
                    color,
                    0.0f,
                    new Vector2(graphic.Width, graphic.Height),
                    1.0f,
                    SpriteEffects.FlipHorizontally,
                    1.0f);
                batch.Draw(
                    graphic,
                    position,
                    null,
                    color,
                    (float)Math.PI,
                    new Vector2(0, graphic.Height),
                    1.0f,
                    SpriteEffects.None,
                    1.0f);
                batch.Draw(
                    graphic,
                    position,
                    null,
                    color,
                    (float)Math.PI,
                    new Vector2(graphic.Width, graphic.Height),
                    1.0f,
                    SpriteEffects.FlipHorizontally,
                    1.0f);
            }
        }
    }
}
